/*
 * Copyright 2014 Walter Lütgenau.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package offset.nodes.client.dialog.menu.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.net.URL;
import java.util.Stack;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import offset.nodes.client.dialog.navigation.model.DialogAppletContext;
import offset.nodes.client.dialog.navigation.model.JSEvent;
import offset.nodes.client.dialog.navigation.model.JSNode;
import offset.nodes.client.dialog.navigation.model.JSUtil;
import offset.nodes.client.dialog.navigation.model.JSWindow;
import offset.nodes.client.view.BaseApplet;

/**
 * Implements a menu applet.
 * 
 * @author Walter Lütgenau
 */
public class MenuApplet extends BaseApplet {
    public static final String PAR_MENU = "menu";
    public static final String DELIMITER_ACTION = "=";
    public static final String ACTION_JSF = "jsf";
    public static final String ACTION_APPLET = "applet";

    JFrame frame;
    JPopupMenu menu;
    JLabel label;
    
    @Override
    public void initUI() {        
        frame = new JFrame();
        
        frame.setUndecorated(true);
        frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);        

        label = new JLabel();
        label.setPreferredSize(new Dimension(1, 1));
        frame.add(label);
        frame.pack();

        menu = new JPopupMenu();        
        menu.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
        addMenuItems(menu);        
        menu.addPopupMenuListener(new PopupMenuListener() {

            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                
            }

            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                setVisible(false);
                frame.dispose();
            }

            public void popupMenuCanceled(PopupMenuEvent e) {

            }

        });
        
        // Determine variables for calculating frame position. Position should be below the calling element.
        DialogAppletContext context = (DialogAppletContext) getAppletContext();
        Point location = JSUtil.getLowerLeftEdge(context.getCallingNode(), context.getEvent());
        
        // Set frame position
        frame.setLocation((int) location.getX(), (int) location.getY());        
    }
    
    /**
     * Creates a menu structure from MenuHandler events.
     * 
     * This structure can be transferred to a popup menu, s. addToPopup.
     */
    class DefaultMenuHandler implements MenuHandler {
        Stack<JMenu> menus = new Stack<JMenu>();
        JSWindow window;
        JSNode element;
        JSEvent event;
        boolean inItem = false;
        
        public DefaultMenuHandler(JSWindow window, JSNode element, JSEvent event) {
            menus.push(new JMenu());
            this.window = window;
            this.element = element;
            this.event = event;
        }
        
        @Override
        public void startItem(String label, String iconLocation, String action) {
            Icon icon = null;
            if (iconLocation != null && iconLocation.length() > 0) {
                URL iconUrl = this.getClass().getResource(iconLocation);
                if (iconUrl != null)
                    icon = new ImageIcon(iconUrl);
            }
            
            if (action == null || action.length() == 0) { // a menu
                JMenu newMenu = new JMenu(label);
                newMenu.setBackground(Color.WHITE);
                newMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
                if (icon != null)
                    newMenu.setIcon(icon);
                
                menus.peek().add(newMenu);
                menus.push(newMenu);
                inItem = false;
            } else { // a menu item
                JMenuItem newItem = new JMenuItem();
                newItem.setBackground(Color.WHITE);      
                
                String[] actionParameters = action.split(DELIMITER_ACTION);
                if (actionParameters[0].equals(ACTION_APPLET)) {
                    if (icon != null)
                        newItem.setAction(new AppletAction(label, icon, window, actionParameters[1], element, event));
                    else
                        newItem.setAction(new AppletAction(label, window, actionParameters[1], element, event));
                } else if (actionParameters[0].equals(ACTION_JSF)) {
                    if (icon != null)
                        newItem.setAction(new JSFAction(label, icon, window, actionParameters[1]));
                    else
                        newItem.setAction(new JSFAction(label, window, actionParameters[1]));
                }
                
                menus.peek().add(newItem);
                inItem = true;
            }
        }

        @Override
        public void endItem() {
            if (!inItem)
                menus.pop();
            inItem = false;
        }
        
        /**
         * Add the menu structure built up internally to a
         * JPopupMenu provided by the caller.
         * 
         * @param popup the popup menu.
         */
        public void addToPopup(JPopupMenu popup) {
            JMenu root = (JMenu) menus.get(0);
            int count = root.getItemCount();
            for (int i = 0; i < count; i++)
                popup.add(root.getItem(0));
        }
        
    }
    
    /**
     * Retrieve the menu parameter, parse it
     * and add the menu items to the popup menu.
     * 
     * @param menu the popup menu.
     */
    protected void addMenuItems(JPopupMenu menu) {
        String items = getParameter(PAR_MENU);
        DialogAppletContext context = (DialogAppletContext) getAppletContext();
        DefaultMenuHandler handler = new DefaultMenuHandler(context.getWindow(), context.getCallingNode(), context.getEvent());
        
        MenuParser parser = new MenuParser(items, handler);
        parser.parse();
        
        handler.addToPopup(menu);
    }
    
    @Override
    public void startUI() {
        frame.setVisible(true);        
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                menu.show(label, 0, 0);
            }
        });            
    }    
}
